﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using Lon.Util;
using System.IO;
using System.Net;
using System.Diagnostics;
using Lon.Data;
using Lon.IO;
using LonLog;

namespace Lon.Server
{
    public class FrontServerNode : Lon.Server.IFrontServer 
    {
        protected Socket clientSocket;
        private AppServer appServer;
        DataPackageProcessService realTimeProessService=new DataPackageProcessService();
        DataPackageProcessService dataAccessService = new DataPackageProcessService();
        NetNodeManager netNodeManager;
        public event EventHandler<RawDataUpdateEventArgs> DataUpdateHandler;

         
        public AppServer AppServer
        {
            get { return appServer; }
        }

        public Socket ClientSocket
        {
            get { return clientSocket; }
        }
        protected String dbm;
        public int Id { get; protected set; }

        public String Dbm
        {
            get { return dbm; }
        }

        private List<int> listenList = new List<int>();

        public List<int> ListenList
        {
            get { return listenList; }

        }

        public FrontServerNode(Socket s, AppServer appServer)
        {
            this.clientSocket = s;
            this.appServer = appServer;
            netNodeManager=appServer.NetNodeManager;
            realTimeProessService.RegDataPackageProcessProvider(0x17, new CSMRtKglPackageProcess(netNodeManager));
            realTimeProessService.RegDataPackageProcessProvider(0x23, new ConnectStatusProcess(netNodeManager, this));
            dataAccessService.RegDataPackageProcessProvider(0x1A, new  TjwxRtAlarmProcess(netNodeManager,this));
            dataAccessService.RegDataPackageProcessProvider(0x13, new CSMDayReportProvider(this));
            dataAccessService.RegDataPackageProcessProvider(0x21, new CSMConfigFileProvider(this));               
        }

        public void SendHeartbeat()
        {
            RealSend(DataFrame.GetHeartbeat());
        }

       
        public void RealSend(Byte[] buf)
        {
            if (this.clientSocket == null) return;
            if (this.clientSocket.Connected == false) return;
            try
            {
                
                this.clientSocket.Send(buf);
              
            }
            catch (System.Exception ex)
            {
                //this.appServer.RemoveClient(this);

            }
        }

    

        public virtual void SendMessage(DataFrame df)
        {
            if (this.clientSocket == null) return;



            if (this.clientSocket.Connected == false) return;
         
            DataLog(df, Lon.Data.DataDir.Transmit);
            RealSend(df);
           
          
          
        }

        byte[] rxBuf = new byte[1024*1024*8];

        protected virtual void RxProc(object obj)
        {
            while (true)
            {
                try
                {
                    int bytes = 0;
                    int rxPoint = 0;
                    while (rxPoint < 4)
                    {
                        bytes = clientSocket.Receive(rxBuf, rxPoint, 16 - rxPoint, SocketFlags.None);
                        rxPoint += bytes;
                    }
                    int maxCount = rxBuf[0] + (rxBuf[1] << 8) + (rxBuf[2] << 16) + (rxBuf[3] << 24);
                    maxCount += 5;
                    if (maxCount >= rxBuf.Length)
                    {
                        clientSocket.Disconnect(true);
                    }
                    while (rxPoint < maxCount)
                    {
                        try
                        {
                            bytes = clientSocket.Receive(rxBuf, rxPoint, maxCount - rxPoint, SocketFlags.None);
                            //String str = StringHelper.ByteArr2HexString(rxBuf, rxPoint, bytes, " ");
                            //File.AppendAllText("dataLog.Txt", str + "\r\n");
                        }
                        catch (System.Exception ex)
                        {
                            LogHelper.WriteLog("", LogType.Info, ex.Message);
                        }

                        rxPoint += bytes;
                    }
                    byte[] dataBuf = new byte[maxCount];
                    Array.Copy(rxBuf, 0, dataBuf, 0, maxCount);
                    try
                    {
                         DataFrame df = new DataFrame(dataBuf,true);
                         DataLog(df, Lon.Data.DataDir.Recive);
                         DealDataFrame(df);
                    }
                    catch(Exception ex)
                    {
                        LogHelper.WriteLog("", LogType.Info, ex.Message);
                        NetDebugConsole.WriteLine(ex.Message+ex.StackTrace);
                    }

                }
                catch (System.Exception ex)
                {
                    LogHelper.WriteLog("", LogType.Info,
                           ex.Message);
                    RemoveFormSeverDict();
                    return;
                }
            }

        }
        private List<NetRawDataRec> rawDataRecs = new List<NetRawDataRec>(200);
        private void DataLog(DataFrame df, Lon.Data.DataDir dir)
        {
            if (df.DataFrameFlag == DataFrameFlag.Heartbeat) // 不显示心跳帧   
            {
                return;
            }
            NetRawDataRec rec = new NetRawDataRec(df, dir);

            lock (this.rawDataRecs)
            {
                if (this.rawDataRecs.Count > this.MaxCount)
                {
                    this.rawDataRecs.RemoveAt(0);
                }
                this.rawDataRecs.Add(rec);
            }
            this.DoDataUpdateHandler(rec);
        }
        private void DoDataUpdateHandler(NetRawDataRec rec)
        {
            EventHandler<RawDataUpdateEventArgs> temp = DataUpdateHandler;
            if (temp == null) return;
            RawDataUpdateEventArgs args = new RawDataUpdateEventArgs(rec);
            temp(this, args);
        }
        private void RemoveFormSeverDict()
        {
            lock (this.appServer.clientSocketDict)
            {
                if (this.appServer.clientSocketDict.ContainsKey(this.clientSocket))
                    this.appServer.clientSocketDict.Remove(this.clientSocket);
            }

            lock (this.appServer.clientDbmDict)
            {
                if (this.appServer.clientDbmDict.ContainsKey(this.Id))
                    this.appServer.clientDbmDict.Remove(this.Id);
            }

        }

        protected  DateTime lastHeartbeatTime;

        public DateTime LastHeartbeatTime
        {
            get { return lastHeartbeatTime; }

        }

        private NodeType clientType = NodeType.Unknow;

        public NodeType ClientType
        {
            get { return clientType; }
        }

        protected virtual void DealDataFrame(DataFrame df)
        {  
            if (df.DataFrameFlag == DataFrameFlag.Heartbeat)
            {
                lastHeartbeatTime = DateTime.Now;
                return;
            }
            this.appServer.Process(df, this);
            //realTimeProessService.ProcessDataFrame(df);
            //dataAccessService.ProcessDataFrame(df);
         
           
        }

        private void GetClientType(DataFrame df)
        {
            if (this.clientType != NodeType.Unknow) return;
            if (df.IsCommand)
            {
                this.clientType = NodeType.Terminal;
            }
            else
            {
                this.clientType = NodeType.Station;
            }
        }

        private void GetLinsenStation(DataFrame df)
        {
            if (!df.IsCommand) return;
            if (df.DstId == this.appServer.InterfaceId) return;
            if (this.listenList.Contains(df.DstId)) return;
            this.listenList.Add(df.DstId);
            if (this.listenList.Count > 4)
            {
                this.listenList.RemoveAt(0);
            }
        }
        /// <summary>
        /// 从数据帧中获取本站的电报码及Id
        /// </summary>
        /// <param name="df"></param>
        private void GetThisIdAndDbm(DataFrame df)
        {
            if (String.IsNullOrEmpty(this.dbm))
            {
                this.dbm = df.SrcDbm;
            }
            else if (this.dbm != df.SrcDbm)
            {
                lock (this.appServer.clientDbmDict)
                {
                    this.appServer.clientDbmDict.Remove(this.Id);
                
                }
            }
            if (this.Id == 0)
            {
                this.Id = df.SrcId;
                this.appServer.clientDbmDict[this.Id] = this;
            }
            else if (this.Id != df.SrcId)
            {
                lock (this.appServer.clientDbmDict)
                {
                    this.appServer.clientDbmDict.Remove(this.Id);
                    this.Id = df.SrcId;
                    this.appServer.clientDbmDict[this.Id] = this;
                }
            }
        }

        private void DealConfigFileRequest(DataFrame df)
        {

            if (df.MajorDataType != MajorDataType.ConfigFileMessage) return;

            if (!this.listenList.Contains(df.DstId))
                this.listenList.Add(df.DstId);
            if (this.listenList.Count > 4)
            {
                this.listenList.RemoveAt(0);
            }
            this.appServer.SendToAppSever(df);

        }

        protected virtual void SendToDstId(DataFrame df)
        {
            FrontServerNode sc = null;
            lock (this.appServer.clientDbmDict)
            {

                if (!this.appServer.clientDbmDict.ContainsKey(df.DstId))
                {
                    this.appServer.SendToBalance(df);
                    return;
                }
                sc = this.appServer.clientDbmDict[df.DstId];
            }
            if (sc == null) return;
            sc.SendMessage(df);
        }

        private void SendAck(DataFrame df)
        {
            DataFrame ackFrame = df.Clone();
            ackFrame.DstId = df.SrcId;
            ackFrame.SrcId = df.DstId;
           
            RealSend(df);
            
        }

        void RealSend(DataFrame df)
        { 
            DataLog(df, Lon.Data.DataDir.Transmit);
            RealSend(df.Buf);
        }

        private void SendMutlicastFrame(DataFrame df)
        {
            TransType tt = df.GetTransType();
            if (tt == TransType.ToAllClientAndAck)
            {
                if (this.clientType != NodeType.Terminal) return;
                DataFrame newFrame = df.Clone();
                newFrame.DstId = this.Id;
                RealSend(newFrame);
            }
            else if (tt == TransType.ToConnectedClient)
            {
                if (!this.listenList.Contains(df.SrcId)) return;
                DataFrame newFrame = df.Clone();
                newFrame.DstId = this.Id;

                RealSend(newFrame);
            }
        }

        private static byte[] HeartbeatData = new byte[] { 0x0B, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
        
        public static byte[] GetHeartbeat()
        {
            //心跳帧
            return HeartbeatData;
        }

        #region IRawDataProvider 成员
        public override string ToString()
        {
            return Name;
        }

        public virtual string Name
        {
          
            get 
            {  
                IPEndPoint ipep=(IPEndPoint)this.ClientSocket.RemoteEndPoint;
                return String.Format("[{0}] {1}{2}", new object[] { Dbm, ipep.Address, ipep.Port }); 
            }
        }

        public string NameDesp
        {
            get
            {
                return Name;
            }
        }
       

        public int MaxCount
        {
            get
            {
                return 198;
            }
            set
            {
               
            }
        }


        #endregion

        public virtual void Start()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(RxProc));
            realTimeProessService.Start();
            dataAccessService.Start();
        }


        private ManualResetEvent connectDone = new ManualResetEvent(false);


        #region IFrontServer 成员

        public bool Connected
        {
            get 
            {
                try
                {
                    if (this.clientSocket == null)
                    {
                        return false;
                    }
                    return this.clientSocket.Connected;
                }
                catch 
                {
                    return false;
                }


            }
        }

        #endregion
    }

   

}
